
import { notification, message } from 'antd';
import { isNumber, isEmpty } from 'lodash';


const codeMessage = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队（异步任务）。',
  204: '删除数据成功。',
  400: '发出的请求有错误，服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限（令牌、用户名、密码错误）。',
  403: '用户得到授权，但是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录，服务器没有进行操作。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除，且不会再得到的。',
  422: '当创建一个对象时，发生一个验证错误。',
  500: '服务器发生错误，请检查服务器。',
  502: '网关错误。',
  503: '服务不可用，服务器暂时过载或维护。',
  504: '网关超时。',
};

/**
 * 异常处理程序
 */
const errorHandler = (response: Response): Response => {
  // 如果请求正常返回
  if (response && response.status) {
    const { status, url } = response;
    // 如果状态码为401并且url请求符合同源策略(因为可能请求其他域名的接口)，则跳转到登录页
    if (
      [401].includes(response.status) &&
      url.indexOf(window.location.host) >= 0
    ) {
      localStorage.clear();
      window.location.replace('/user/login')

      return response;
    }
    if (![200].includes(response.status)) {
      // 其他状态码的处理
      const errorText = codeMessage[response.status] || response.statusText;

      notification.error({
        message: `请求错误 ${status}: ${url}`,
        description: errorText,
      });
    }
  } else if (!response) {
    // 如果请求没有正常返回结果
    notification.error({
      description: '您的网络发生异常，无法连接服务器',
      message: '网络异常',
    });
  }
  return response;
};

const request = async (
  input: RequestInfo,
  init?: RequestInit | undefined,
): Promise<any> => {
  return new Promise<Response>((resolve, reject) => {
    const res = fetch(input, init)
      .then((response) => {
        return errorHandler(response);
      })
      .then((result) => result.json());

    resolve(res);
  });
};

interface IOptions {
  data?: any;
  [x: string]: any;
}

const MYrequest = async (url: string, options: IOptions) => {
  const newoptions = options;

  let reponseRes = { msg: null, success: false };

  const method = options?.method || 'GET';
  const body = method === 'GET' ? null : JSON.stringify(newoptions?.data);
  const defaultHeaders = {
    ...options?.headers,
    'content-type': 'application/json',
  };

  // 当前时间
  const nowTime = new Date().getTime();
  // token过期时间
  const tokenExpires = Number(localStorage.getItem('tokenExpires'));
  // `/api/account/refreshtoken`接口需要的参数
  const refreshToken = localStorage.getItem('refreshToken');
  let token = localStorage.getItem('token');

  /*
  如果url不是单点登录的接口
  并且需要的参数都存在，
  4*60*60*1000= 14400000
  token过期时间减去当前时间小于 4小时

  则获取新的token
  */
  if (
    url.indexOf('/api/account/ssologin') < 0 &&
    token &&
    refreshToken &&
    isNumber(tokenExpires) &&
    tokenExpires > 0 &&
    tokenExpires - nowTime < 14400000
  ) {
    // token失效前4小时刷新
    const res = await request(`/api/account/refreshtoken`, {
      method: 'POST',
      headers: { Authorization: `${token}`, ...defaultHeaders },
      body: JSON.stringify({ refreshToken }),
    });
    if (!res.data) {
      return {};
    }

    const { token: newtoken, refreshToken: newrefreshToken, expire } = res.data;

    token = newtoken;
    localStorage.setItem('token', newtoken);
    localStorage.setItem('refreshToken', newrefreshToken);
    localStorage.setItem(
      'tokenExpires',
      `${new Date().getTime() + expire * 1000}`,
    );
  }
  // 已经发布的大屏或者仪表盘页面 接口不需要token
  const bool1 = window.location.pathname.includes('noAuthority') && !token;

  // 登录接口不需要token
  const bool2 =
    url.includes('/api/account/login') &&!token;

  // 其他需要 token的业务接口
  const bool3 =
    url.indexOf('/api/account/login') <= 0  &&token;

  const isNeedToken = bool3 && !bool1 && !bool2;

  reponseRes = await request(url, {
    method,
    headers: isNeedToken
      ? { Authorization: `${token}`, ...defaultHeaders }
      : defaultHeaders,
    body,
  });

  // 如果是登录接口，则缓存token
  if (reponseRes && reponseRes.data && reponseRes.data.token) {
    const {
      token: newtoken,
      refreshToken: newrefreshToken,
      expire,
    } = reponseRes.data;

    token = newtoken;
    localStorage.setItem('token', newtoken);
    localStorage.setItem('refreshToken', newrefreshToken);
    localStorage.setItem(
      'tokenExpires',
      `${new Date().getTime() + expire * 1000}`,
    );
  }
  if (reponseRes && reponseRes.msg && !reponseRes.success) {
    message.error(reponseRes.msg);

    return {};
  }
  return reponseRes;
};

export default MYrequest;
